<!DOCTYPE html>
            
<HTML>
<HEAD>
<meta name="booktitle" content="Developing Applications With Objective Caml" >
 <meta charset="ISO-8859-1"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<META name="GENERATOR" content="hevea 1.05-7 of 2000-02-24">
<META NAME="Author" CONTENT="Christian.Queinnec@lip6.fr">
<LINK rel=stylesheet type="text/css" href="videoc-ocda.css">
<script language="JavaScript" src="videoc.js"><!--
//--></script>
<TITLE>
 Other Object-oriented Features
</TITLE>
</HEAD>
<BODY class="regularBody">
<A HREF="book-ora141.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora143.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
<HR>

<H2> Other Object-oriented Features</H2><A NAME="toc202"></A>
<H3> References: <TT>self</TT> and <TT>super</TT></H3>
<A NAME="@concepts310"></A>
<A NAME="@concepts311"></A>
<A NAME="@concepts312"></A>
<A NAME="sec-self-super"></A>
When defining a method in a class, it may be convenient to be able to invoke
a method from a parent class. For this purpose, Objective CAML allows
the object itself, as well as (the objects of) the parent class to be named. In the former case,
the chosen name is given after the keyword <B>object</B>, and in the latter,
after the inheritance declaration.<BR>
<BR>
For example, in order to define the method <TT>to_string</TT> of colored points,
it is better to invoke the method <TT>to_string</TT> from the parent class and
to extend its behavior with a new method, <TT>get_color</TT>.


<PRE><BR># <B>class</B><CODE> </CODE>colored_point<CODE> </CODE><TT>(</TT>x<CODE>,</CODE>y<TT>)</TT><CODE> </CODE>c<CODE> </CODE><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><CODE> </CODE><TT>(</TT>self<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE>point<CODE> </CODE><TT>(</TT>x<CODE>,</CODE>y<TT>)</TT><CODE> </CODE><B>as</B><CODE> </CODE>super<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>c<CODE> </CODE><CODE>=</CODE><CODE> </CODE>c<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>get_color<CODE> </CODE><CODE>=</CODE><CODE> </CODE>c<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>to_string<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>super#to_string()<CODE> </CODE><CODE>^</CODE><CODE> </CODE><CODE> </CODE><CODE>" ["</CODE><CODE> </CODE><CODE>^</CODE><CODE> </CODE>self#get_color<CODE> </CODE><CODE>^</CODE><CODE> </CODE><CODE>"] "</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR>

</PRE>
<BR>
<BR>
Arbitrary names may be given to the parent and child class objects, but
the names <TT>self</TT> and
<TT>this</TT> for the current class and <TT>super</TT> for the
parent are conventional. Choosing other names may be useful with multiple
inheritance since it makes it easy to differentiate the parents
(see page <A HREF="book-ora143.html#subsec-heritage-multiple">??</A>). <BR>
<BR>


<H3> Warning </H3> <HR>

You may not reference a variable of an instance's parent if you declare a new
variable with the same name since it masks the former.


<HR>

<BR>
<BR>
<A NAME="toc203"></A>
<H3> Delayed Binding</H3>
<A NAME="subsubsec-liaison-retardee"></A>
<A NAME="@concepts313"></A>
With delayed binding the method used when a
message is sent is decided at run-time; this is opposed to static
binding where the decision is made at compile time. In Objective CAML, delayed binding of
methods is used; therefore, the exact piece of code to be executed is determined
by the recipient of the message.<BR>
<BR>
The above declaration of class <I>colored_point</I> redefines the method
<TT>to_string</TT>. This new definition uses method <TT>get_color</TT> from
this class. Now let us define another class <I>colored_point_1</I>,
inheriting from <I>colored_point</I>; this new class redefines method
<TT>get_color</TT> (testing that the character string is appropriate), but
does not redefine <TT>to_string</TT>.<BR>
<BR>


<PRE><BR># <B>class</B><CODE> </CODE>colored_point_1<CODE> </CODE>coord<CODE> </CODE>c<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE>colored_point<CODE> </CODE>coord<CODE> </CODE><CODE> </CODE>c<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>true_colors<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>[</CODE><CODE>"white"</CODE>;<CODE> </CODE><CODE>"black"</CODE>;<CODE> </CODE><CODE>"red"</CODE>;<CODE> </CODE><CODE>"green"</CODE>;<CODE> </CODE><CODE>"blue"</CODE>;<CODE> </CODE><CODE>"yellow"</CODE><CODE>]</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>get_color<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>if</B><CODE> </CODE>List.mem<CODE> </CODE>c<CODE> </CODE>true_colors<CODE> </CODE><B>then</B><CODE> </CODE>c<CODE> </CODE><B>else</B><CODE> </CODE><CODE>"UNKNOWN"</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR>

</PRE>
<BR>
<BR>
Method <TT>to_string</TT> is the same in both classes of colored points; but
two objects from these classes will have a different behavior.


<PRE><BR># <B>let</B><CODE> </CODE>p1<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>colored_point<CODE> </CODE><TT>(</TT><CODE>1</CODE><CODE>,</CODE><CODE>1</CODE><TT>)</TT><CODE> </CODE><CODE>"blue as an orange"</CODE><CODE> </CODE>;;<BR><CODE>val p1 : colored_point = &lt;obj&gt;</CODE><BR># p1#to_string();;<BR><CODE>- : string = "( 1, 1) [blue as an orange] "</CODE><BR># <B>let</B><CODE> </CODE>p2<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>colored_point_1<CODE> </CODE><TT>(</TT><CODE>1</CODE><CODE>,</CODE><CODE>1</CODE><TT>)</TT><CODE> </CODE><CODE>"blue as an orange"</CODE><CODE> </CODE>;;<BR><CODE>val p2 : colored_point_1 = &lt;obj&gt;</CODE><BR># p2#to_string();;<BR><CODE>- : string = "( 1, 1) [UNKNOWN] "</CODE><BR>

</PRE>
<BR>
<BR>
The binding of <TT>get_color</TT> within <TT>to_string</TT> is not fixed
when the class <I>colored_point</I> is compiled. The code to be executed
when invoking the method <TT>get_color</TT> is determined from the methods
associated with instances of classes <I>colored_point</I> and
<I>colored_point_1</I>. For an instance of <I>colored_point</I>,
sending the message <TT>to_string</TT> causes the execution of
<TT>get_color</TT>, defined in class <I>colored_point</I>. On the other
hand, sending the same message to an instance of <I>colored_point_1</I>
invokes the method from the parent class, and the latter triggers method
<TT>get_color</TT> from the child class, controlling the relevance of the
string representing the color.<BR>
<BR>
<A NAME="toc204"></A>
<H3> Object Representation and Message Dispatch</H3>
<A NAME="sec-dispatch"></A>
An object is split in two parts: one may vary, the other is fixed. The varying
part contains the instance variables, just as for a record. The fixed part
corresponds to a methods table, shared by all instances of the class.<BR>
<BR>
The methods table is a sparse array of functions. Every method name in an application
is given a unique id that serves as an index into the methods table.
We assume the existence of a machine instruction
<TT>GETMETHOD(o,n)</TT>, that takes two parameters: an object <TT>o</TT> and an
index <TT>n</TT>. It returns the function associated with this index in the
methods table. We write <TT>f_n</TT> for the result of the call
<TT>GETMETHOD(o,n)</TT>. Compiling the message send <EM>o#m</EM> computes the
index <TT>n</TT> of the method name <TT>m</TT> and produces the code for applying
<TT>GETMETHOD(o,n)</TT> to object <TT>o</TT>. This corresponds to applying
function <TT>f_n</TT> to the receiving object <TT>o</TT>. Delayed binding is
implemented through a call to <TT>GETMETHOD</TT> at run time.<BR>
<BR>
Sending a message to <TT>self</TT> within a method is also compiled as a search
for the index of the message, followed by a call to the function found
in the methods table.<BR>
<BR>
In the case of inheritance, since the method name always has the same index, regardless of
redefinition, only the entry in new class' methods table is changed for redefinitions. So sending
message <TT>to_string</TT> to an instance of class <TT>point</TT> will apply
the conversion function of a point, while sending the same message to an
instance of <TT>colored_point</TT> will find at the same index the function
corresponding to the method which has been redefined to recognize the
color field.<BR>
<BR>
Thanks to this index invariance, subtyping (see page <A HREF="book-ora144.html#sec-sous-typage">??</A>)
is insured to be coherent with respect to the execution. Indeed if a colored
point is explicitly constrained to be a point, then upon sending the message
<TT>to_string</TT> the method index from class <TT>point</TT> is computed,
which coincides with that from class <TT>colored_point</TT>. Searching for the
method will be done within the table associated with the receiving instance,
i.e. the <TT>colored_point</TT> table.<BR>
<BR>
Although the actual implementation in Objective CAML is different, the principle of dynamic search
for the method to be used is still the same.<BR>
<BR>
<A NAME="toc205"></A>
<H3> Initialization</H3>
<A NAME="@fonctions390"></A>
The class definition keyword <B>initializer</B> is used
to specify code to be executed during object construction. An
initializer can perform any computation and field access that is legal in a method.


<H3> Syntax </H3> <HR>


<B>initializer</B> <I>expr</I>



<HR>

<BR>
<BR>
Let us again extend the class <TT>point</TT>, this time by defining a verbose
point that will announce its creation.


<PRE><BR># <B>class</B><CODE> </CODE>verbose_point<CODE> </CODE>p<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><TT>(</TT>self<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE>point<CODE> </CODE>p<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>initializer</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>xm<CODE> </CODE><CODE>=</CODE><CODE> </CODE>string_of_int<CODE> </CODE>x<CODE> </CODE><B>and</B><CODE> </CODE>ym<CODE> </CODE><CODE>=</CODE><CODE> </CODE>string_of_int<CODE> </CODE>y<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>Printf.printf<CODE> </CODE><CODE>"&gt;&gt; Creation of a point at (%s %s)\n"</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>xm<CODE> </CODE>ym<CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.printf<CODE> </CODE><CODE>"   , at distance %f from the origin\n"</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>self#distance()<TT>)</TT><CODE> </CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR>

</PRE>



<PRE><BR># <B>new</B><CODE> </CODE>verbose_point<CODE> </CODE><TT>(</TT><CODE>1</CODE><CODE>,</CODE><CODE>1</CODE><TT>)</TT>;;<BR><CODE>&gt;&gt; Creation of a point at (1 1)</CODE><BR><CODE>   , at distance 1.414214 from the origin</CODE><BR><CODE>- : verbose_point = &lt;obj&gt;</CODE><BR>

</PRE>
<BR>
<BR>
An amusing but instructive use of initializers is tracing class
inheritance on instance creation. Here is an example:


<PRE><BR># <B>class</B><CODE> </CODE>c1<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>initializer</B><CODE> </CODE>print_string<CODE> </CODE><CODE>"Creating an instance of c1\n"</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><BR># <B>class</B><CODE> </CODE>c2<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE>c1<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>initializer</B><CODE> </CODE>print_string<CODE> </CODE><CODE>"Creating an instance of c2\n"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><BR># <B>new</B><CODE> </CODE>c1<CODE> </CODE>;;<BR><CODE>Creating an instance of c1</CODE><BR><CODE>- : c1 = &lt;obj&gt;</CODE><BR># <B>new</B><CODE> </CODE>c2<CODE> </CODE>;;<BR><CODE>Creating an instance of c1</CODE><BR><CODE>Creating an instance of c2</CODE><BR><CODE>- : c2 = &lt;obj&gt;</CODE><BR>

</PRE>

Constructing an instance of <I>c2</I> requires first constructing
an instance of the parent class. <BR>
<BR>
<A NAME="toc206"></A>
<H3> Private Methods</H3>
<A NAME="@fonctions391"></A>
<A NAME="subsubsec-private-method"></A>
A method may be declared private with the keyword
<B>private</B>. It will appear in the interface to the class but not in 
instances of the class. A private method can only be invoked from other
methods; it cannot be sent to an instance of the class. However,
private methods are inherited, and therefore can be used in definitions of the
hierarchy<A NAME="text39" HREF="book-ora150.html#note39"><SUP><FONT SIZE=2>3</FONT></SUP></A>. 


<H3> Syntax </H3> <HR>


<B>method</B> <B>private</B> <I>name</I> = <I>expr</I>



<HR>

<BR>
<BR>
Let us extend the class <I>point</I>: we add a method <TT>undo</TT> that revokes the
last move. To do this, we must remember the
position held before performing a move, so we introduce two new fields,
<TT>old_x</TT> and <TT>old_y</TT>, together with their update method. Since
we do not want the user to have direct access to this method, we declare it as
private. We redefine the methods <TT>moveto</TT> and <TT>rmoveto</TT>,
keeping note of the current position before calling the previous methods for
performing a move.


<PRE><BR># <B>class</B><CODE> </CODE>point_m1<CODE> </CODE><TT>(</TT>x0<CODE>,</CODE>y0<TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><TT>(</TT>self<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE>point<CODE> </CODE><TT>(</TT>x0<CODE>,</CODE>y0<TT>)</TT><CODE> </CODE><B>as</B><CODE> </CODE>super<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE><B>mutable</B><CODE> </CODE>old_x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x0<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE><B>mutable</B><CODE> </CODE>old_y<CODE> </CODE><CODE>=</CODE><CODE> </CODE>y0<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE><B>private</B><CODE> </CODE>mem_pos<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>old_x<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>x<CODE> </CODE>;<CODE> </CODE>old_y<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>y<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>undo<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>old_x;<CODE> </CODE>y<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>old_y<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>moveto<CODE> </CODE><TT>(</TT>x1<CODE>,</CODE><CODE> </CODE>y1<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE>self#mem_pos<CODE> </CODE>()<CODE> </CODE>;<CODE> </CODE>super#moveto<CODE> </CODE><TT>(</TT>x1<CODE>,</CODE><CODE> </CODE>y1<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>rmoveto<CODE> </CODE><TT>(</TT>dx<CODE>,</CODE><CODE> </CODE>dy<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE>self#mem_pos<CODE> </CODE>()<CODE> </CODE>;<CODE> </CODE>super#rmoveto<CODE> </CODE><TT>(</TT>dx<CODE>,</CODE><CODE> </CODE>dy<TT>)</TT><BR><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><CODE>class point_m1 :</CODE><BR><CODE>  int * int -&gt;</CODE><BR><CODE>  object</CODE><BR><CODE>    val mutable old_x : int</CODE><BR><CODE>    val mutable old_y : int</CODE><BR><CODE>    val mutable x : int</CODE><BR><CODE>    val mutable y : int</CODE><BR><CODE>    method distance : unit -&gt; float</CODE><BR><CODE>    method get_x : int</CODE><BR><CODE>    method get_y : int</CODE><BR><CODE>    method private mem_pos : unit -&gt; unit</CODE><BR><CODE>    method moveto : int * int -&gt; unit</CODE><BR><CODE>    method rmoveto : int * int -&gt; unit</CODE><BR><CODE>    method to_string : unit -&gt; string</CODE><BR><CODE>    method undo : unit -&gt; unit</CODE><BR><CODE>  end</CODE><BR>

</PRE>
<BR>
<BR>
We note that method <TT>mem_pos</TT> is preceded by the keyword
<B>private</B> in type <I>point_m1</I>.
It can be invoked from within method <TT>undo</TT>, but not on
another instance.
The situation is the
same as for instance variables. Even though fields <TT>old_x</TT> and
<TT>old_y</TT> appear in the results shown by compilation, that does not imply
that they may be handled directly (see page <A HREF="book-ora140.html#subsec-class-dec">??</A>).


<PRE><BR># <B>let</B><CODE> </CODE>p<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>point_m1<CODE> </CODE><TT>(</TT><CODE>0</CODE><CODE>,</CODE><CODE> </CODE><CODE>0</CODE><TT>)</TT><CODE> </CODE>;;<BR><CODE>val p : point_m1 = &lt;obj&gt;</CODE><BR># p#mem_pos()<CODE> </CODE>;;<BR><CODE>Characters 0-1:</CODE><BR><CODE>This expression has type point_m1</CODE><BR><CODE>It has no method mem_pos</CODE><BR># p#moveto<TT>(</TT><CODE>1</CODE><CODE>,</CODE><CODE> </CODE><CODE>1</CODE><TT>)</TT><CODE> </CODE>;<CODE> </CODE>p#to_string()<CODE> </CODE>;;<BR><CODE>- : string = "( 1, 1)"</CODE><BR># p#undo()<CODE> </CODE>;<CODE> </CODE>p#to_string()<CODE> </CODE>;;<BR><CODE>- : string = "( 0, 0)"</CODE><BR>

</PRE>
<BR>
<BR>


<H3> Warning </H3> <HR>

A type constraint may make public a method declared with attribute <B>private</B>.


<HR>

<BR>
<BR>
<HR>
<A HREF="book-ora141.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora143.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
</BODY>
</HTML>
